package com.tanhua.server.service;

import com.tanhua.autoconfig.template.OssTemplate;
import com.tanhua.commons.constant.Constants;
import com.tanhua.commons.exception.TanHuaException;
import com.tanhua.dubbo.api.db.UserInfoApi;
import com.tanhua.dubbo.api.mongo.CommentApi;
import com.tanhua.dubbo.api.mongo.MovementApi;
import com.tanhua.model.db.UserInfo;
import com.tanhua.model.enums.CommentType;
import com.tanhua.model.mongo.Comment;
import com.tanhua.model.mongo.Movement;
import com.tanhua.model.mongo.MovementTimeLine;
import com.tanhua.model.vo.*;
import com.tanhua.server.interceptor.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.bson.types.ObjectId;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class MovementService {

    @DubboReference
    private MovementApi movementApi;

    @Autowired
    private OssTemplate ossTemplate;

    @DubboReference
    private UserInfoApi userInfoApi;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @DubboReference
    private CommentApi commentApi;


    /**
     * 动态-发布
     * @param movementVo
     * @param imageContent
     */
    public void postMovement(MovementVo movementVo, MultipartFile[] imageContent) {
        try {
            Long userId = UserHolder.getUserId();   // 获取当前用户的id

            // 文件上传阿里云
            //2.获取图片urls
            List<String> medias = new ArrayList<>();
            if(imageContent != null || imageContent.length > 0){
                for (MultipartFile multipartFile : imageContent) {
                    String originalFilename = multipartFile.getOriginalFilename();

                    String fileName = ossTemplate.upload(originalFilename, multipartFile.getInputStream());
                    medias.add(fileName);
                }
            }

            // 3.构造Movement调用服务
            Movement movement = new Movement();
            BeanUtils.copyProperties(movementVo,movement);  // 文字，经纬度
            movement.setUserId(userId); //动态发布者的用户id
            movement.setLocationName(movementVo.getLocation()); //中文位置名称
            movement.setMedias(medias);

            //4.构造Movement对象调用服务提供者发布动态
            movementApi.publish(movement);

        } catch (IOException e) {
            log.debug("发布动态失败了" + e.getMessage());
            throw new TanHuaException(ErrorResult.error());
        }
    }

    /**
     * 分页查询个人动态
     * @param page
     * @param pageSize
     * @param userId
     * @return
     */
    public PageResult<MovementsVo> findByUserId(Long page, Long pageSize, Long userId) {
        Long loginUserId = UserHolder.getUserId();

        if(userId != null){
            loginUserId = userId;
        }

        //1 调用服务提供者 根据分页参数以及userId 分页查询动态发布表
        PageResult<Movement> movementPageResult = movementApi.findByUserId(page,pageSize,userId);

        if(movementPageResult == null || CollectionUtils.isEmpty(movementPageResult.getItems())){
            return new PageResult<>(0l,10l,0l,1l,null);
        }

        //2 循环遍历动态发布表 根据动态发布的用户id 调用服务提供者 查询用户信息（tb_user_info）
        UserInfo userInfo = userInfoApi.findById(userId);
        //2.1 将List<Movement> 转为 List<MovementsVo>
        List<MovementsVo> movementsVoList = new ArrayList<>();
        for (Movement movement : movementPageResult.getItems()) {

            MovementsVo movementsVo = MovementsVo.init(userInfo, movement);
            // 查询redis中是否有点赞记录，如果有，则将点赞设置为1
            String key = Constants.MOVEMENTS_INTERACT_KEY + movement.getId().toHexString();
            String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
            if(stringRedisTemplate.opsForHash().hasKey(key,hashKey)){
                movementsVo.setHasLiked(1);
            }
            movementsVoList.add(movementsVo);
        }

        //3 构造PageResult<MovementsVo>进行返回
        PageResult<MovementsVo> movementsVoPageResult = new PageResult<>();
        BeanUtils.copyProperties(movementPageResult,movementsVoPageResult); //分页数据
        movementsVoPageResult.setItems(movementsVoList);

        return movementsVoPageResult;
    }

    /**
     * 好友动态
     * @return
     */
    public PageResult<MovementsVo> findFriendMovements(Long page, Long pageSize) {
        Long userId = UserHolder.getUserId();   //当前用户id
        // 调用服务根据用户id查询好友时间线数据
        PageResult<Movement> pageResult = movementApi.findFriendMovements(userId,page,pageSize);

        // 获取动态ids再查询动态表列表数据
        List<Movement> movementList = pageResult.getItems();
        if(pageResult == null || CollectionUtils.isEmpty(movementList)){
            return new PageResult<>(0l,10l,0l,1l,null);
        }

        // 获取动态表的所有作者id，再查询用户信息
        // 基于动态数据与UserInfo数据构造Vo
        List<MovementsVo> movementsVoList = convert2Vo(movementList);

        // 返回vo
        return new PageResult<>(page,pageSize,pageResult.getCounts(),movementsVoList);
    }

    /**
     * 抽取通用方法
     * 把动态信息数据转成voList，并且补全动态作者信息
     * @param movementList
     * @return
     */
    public List<MovementsVo> convert2Vo(List<Movement> movementList){
        // 定义返回的vo数据结果集
        List<MovementsVo> movementsVoList = new ArrayList<>();

        // 收集所有用户ids
        List<Long> listUserIds = movementList.stream().map(Movement::getUserId).collect(Collectors.toList());

        // 获取动态的所有作者的id，再查询用户信息
        Map<Long, UserInfo> userInfoMap = userInfoApi.findByIds(listUserIds, null);

        // 基于动态表和用户信息  构造vo
        for (Movement movement : movementList) {

            MovementsVo movementsVo = MovementsVo.init(userInfoMap.get(movement.getUserId()), movement);

            // 查询redis中是否有点赞记录，如果有，则将点赞设置为1
            String key = Constants.MOVEMENTS_INTERACT_KEY + movement.getId().toHexString();
            String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
            if(stringRedisTemplate.opsForHash().hasKey(key,hashKey)){
                movementsVo.setHasLiked(1);
            }
            movementsVoList.add(movementsVo);
        }

        return movementsVoList;
    }

    /**
     * 推荐动态
     * @param page
     * @param pageSize
     * @return
     */
    public PageResult<MovementsVo> recommend(Long page, Long pageSize) {
        // 根据key查询redis中的Pid
        // set key=Constants.MOVEMENTS_RECOMMEND + UserHolder.getUserId(); value: 1,3,4
        String key = Constants.MOVEMENTS_RECOMMEND + UserHolder.getUserId();
        String pids = stringRedisTemplate.opsForValue().get(key);

        // 定义List<Movement>
        List<Movement> movementList = new ArrayList<>();
        Long counts ; //总记录数

        if (StringUtils.isEmpty(pids)){
            // 没有值 调用服务随机查询10个动态
            movementList = movementApi.randomMovement();
            counts = (long) movementList.size();
        }else {
            // 有值 根据pids调用服务分页查询动态数据
            String[] recommendMovementIdsArr = pids.split(","); // pids又可能大于10条
            counts = Long.valueOf(recommendMovementIdsArr.length);
            long start = (page - 1) * pageSize;
            if(counts > start){
                // 分页查询到需要查询的pids值
                List<Long> listPids = Arrays.stream(recommendMovementIdsArr).skip(start).
                        limit(pageSize).map(idStr -> Long.valueOf(idStr)).collect(Collectors.toList());
                movementList = movementApi.findByPids(listPids);
            }
        }
        // 调用convert2Vo 将List<Movement> 转为 List<MovementVo>
        List<MovementsVo> movementsVoList = convert2Vo(movementList);

        // 返回vo
        return new PageResult<>(page,pageSize,counts,movementsVoList);
    }

    /**
     * 查询单条动态
     * @param movementId
     * @return
     */
    public MovementsVo findById(String movementId) {
        // 根据动态id调用服务查询动态数据
        Movement movement = movementApi.findById1(movementId);

        // 调用服务查询动态作者信息
        UserInfo userInfo = userInfoApi.findById(movement.getUserId());

        // 基于用户信息与动态数据构造vo返回
        MovementsVo movementsVo = MovementsVo.init(userInfo, movement);


        return movementsVo;
    }

    /**
     * 动态点赞
     * @param movementId
     * @return
     */
    public Integer like(String movementId) {
        // 构建comment对象
        Comment com = new Comment();
        com.setCommentType(CommentType.LIKE.getType()); // 设置状态为点赞
        com.setUserId(UserHolder.getUserId());  // 设置评论人的id
        com.setPublishId(new ObjectId(movementId)); // 设置动态id

        Integer count = commentApi.add(com);

        //2、拼接redis的key，将用户的点赞状态存入redis,代表用户已经点赞过了
        // 使用hash结构存储
        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
        stringRedisTemplate.opsForHash().put(key,hashKey,"1");

        return count;
    }

    /**
     * 动态喜欢
     * @param movementId
     * @return
     */
    public Integer love(String movementId) {

        // 构建comment对象
        Comment com = new Comment();
        com.setCommentType(CommentType.LOVE.getType()); // 设置状态为点赞
        com.setUserId(UserHolder.getUserId());  // 设置评论人的id
        com.setPublishId(new ObjectId(movementId)); // 设置动态id

        Integer count = commentApi.add(com);

        //2、拼接redis的key，将用户的点赞状态存入redis,代表用户已经点赞过了
        // 使用hash结构存储

        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashKey = Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();
        stringRedisTemplate.opsForHash().put(key,hashKey,"1");
        return count;
    }

    /**
     * 动态取消点赞
     * @param movementId
     * @return
     */
    public Integer dislike(String movementId) {

        // 构建comment对象
        Comment com = new Comment();
        com.setCommentType(CommentType.LIKE.getType()); // 设置状态为点赞
        com.setUserId(UserHolder.getUserId());  // 设置评论人的id
        com.setPublishId(new ObjectId(movementId)); // 设置动态id

        Integer count = commentApi.remove(com);

        //2、拼接redis的key，将用户的点赞状态存入redis,代表用户已经点赞过了
        // 使用hash结构存储
        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
        stringRedisTemplate.opsForHash().delete(key,hashKey);

        return count;
    }


    /**
     * 动态取消喜欢
     * @param movementId
     * @return
     */
    public Integer unlove(String movementId) {
        // 构建comment对象
        Comment com = new Comment();
        com.setCommentType(CommentType.LOVE.getType()); // 设置状态为点赞
        com.setUserId(UserHolder.getUserId());  // 设置评论人的id
        com.setPublishId(new ObjectId(movementId)); // 设置动态id

        Integer count = commentApi.remove(com);

        //2、拼接redis的key，将用户的点赞状态存入redis,代表用户已经点赞过了
        // 使用hash结构存储
        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashKey = Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();
        stringRedisTemplate.opsForHash().delete(key,hashKey);

        return count;
    }
}
